10539. Почти простые числа
Натуральное число называется
почти простым, если оно не простое и имеет только один простой делитель. Найти
количество почти простых чисел в заданном интервале натуральных чисел.
Вход.
Первая строка содержит количество тестов n (n £ 600). Каждая следующая строка является отдельным тестом и содержит два
числа low и high (0 < low £ high < 1012).
Выход. Для каждого теста вывести в
отдельной строке количество почти простых чисел в промежутке [low.. high]
включительно.
3
1 10
1 20
1 5
Пример выхода
3
4
1
решето Эратосфена - бинарный
поиск
Почти
простые числа имеют вид pk,
где p – простое число, k ³ 2. Например, почти простыми будут 4, 8, 16, 32, 9, 81, … . Поскольку high
< 1012, то исходя из определения почти простого числа p
< 106. Сгенерируем массив primes длины 1000000 = 106,
для которого primes[i] = 1 если i
– простое число и primes[i] = 0 иначе. Далее сгенерируем и отсортируем в
массиве m все почти простые числа (их будет 80071). Обозначим через f(a,
b) количество почти простых чисел в промежутке [a..b].
Тогда f(low, high) = f(1, high) - f(1, low - 1).
Количество почти простых чисел на промежутке [1 .. n] равно номеру места
(индексу), куда можно вставить число n в отсортированный массив m
по верхней границе с учетом сохранения упорядоченности. Номер индекса ищется
бинарным поиском по массиву m при помощи функции upper_bound.
Рассмотрим второй тест. От 1 до
20 находится 4 почти простых числа: 4, 8, 9, 16.
Сгенерируем массив primes для тестирования чисел на
простоту.
void gen_primes(void)
{
int i, j;
for(i = 0;i
< MAX; i++) primes[i] = 1;
for(i = 2; i
<= (int)sqrt(1.0*MAX); i++)
if
(primes[i])
for(j = i
* i; j < MAX; j += i) primes[j] = 0;
}
Для каждого простого числа i
заносим в массив m числа i2, i3,
i4, … пока очередная степень не станет больше 1012.
Переменная ptr содержит индекс последнего почти простого числа, занесенного в
массив m. Поскольку почти простые числа ограничены значением 1012,
то работать следует с 64 битовыми целыми числами (тип long long). Последним
числом в массиве m поставим любое число, большее 1012. Пусть
им будет 1012 + 1. Это следует сделать для корректной работы
последующей функции бинарного поиска.
ptr = -1;
for (i = 2; i < MAX; i++)
if
(primes[i])
{
temp = i;
while
((temp *= i) < 1e12)
m[++ptr] = temp;
}
m[++ptr] = 1e12
+ 1;
Сортируем массив m, используя
STL:
sort(m,m+ptr);
Читаем количество входных тестов n
и для каждого интервала [a, b] вычисляем и выводим значение f(a,
b) = f(1, b) – f(1, a – 1) за константное время.
scanf("%d",&n);
for(test = 1; test <= n; test++)
{
scanf("%lld
%lld",&a,&b);
printf("%d\n",upper_bound(m,m+ptr,b)
- upper_bound(m,m+ptr,a-1));
}